HomeSearch.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. "use client";
  2. import { GameListRep, searchGameListApi, SearchProps } from "@/api/home";
  3. import GroupCard from "@/components/Card/GroupCard";
  4. import { useRouter } from "@/i18n/routing";
  5. import { useSearchStore } from "@/stores/useSearchStore";
  6. import { Button, createErrorBlock, SearchBar } from "antd-mobile";
  7. import { useTranslations } from "next-intl";
  8. import { ChangeEvent, FC, MouseEvent, PropsWithChildren, useRef, useState } from "react";
  9. interface Props {}
  10. interface ContentProps {
  11. closeHandler: () => void;
  12. }
  13. const ErrorBlock = createErrorBlock({
  14. empty: <div className={"iconfont icon-meiyoushuju text-[0.5556rem] text-[#666]"}></div>,
  15. default: <div></div>,
  16. });
  17. const Content: FC<ContentProps> = (props) => {
  18. const t = useTranslations("HomePage");
  19. const { closeHandler } = props;
  20. const [games, setGames] = useState<GameListRep[]>([]);
  21. const searchBarRef = useRef(null);
  22. const [searchValue, setSearchValue] = useState("");
  23. const { history, setHistory, removeKey, removeAllKey } = useSearchStore();
  24. const [visible, setVisible] = useState(false);
  25. const params = useRef<SearchProps>({
  26. current_page: 1,
  27. page_size: 15,
  28. use_page: true,
  29. search_game_name: "",
  30. });
  31. const getGames = async (): Promise<GameListRep[] | undefined> => {
  32. return searchGameListApi(params.current).then((res) => {
  33. setVisible(!res.page.is_end);
  34. if (res.data) {
  35. return res.data;
  36. }
  37. });
  38. };
  39. const isPending = () =>
  40. games.length === 0 &&
  41. params.current.search_game_name === "" &&
  42. params.current.current_page === 1;
  43. const setSearchValueInit = (value: string, isPush = true) => {
  44. params.current.search_game_name = value;
  45. getGames().then((data) => {
  46. if (data && data.length > 0 && value.trim() !== "" && isPush) {
  47. setHistory(value);
  48. }
  49. data && setGames(data);
  50. });
  51. };
  52. // const func = debounce(setSearchValueInit, 500);
  53. // const changeHandler = (value: string) => {
  54. // if (value) func(value);
  55. // };
  56. const blurHandler = (event: ChangeEvent<HTMLInputElement>) => {
  57. const value = event.target.value;
  58. if (value.trim() === "") return;
  59. setSearchValueInit(value);
  60. };
  61. const onCancel = () => {
  62. closeHandler();
  63. params.current.current_page = 1;
  64. params.current.search_game_name = "";
  65. setGames([]);
  66. setVisible(false);
  67. };
  68. // 历史记录单项点击事件
  69. const historyItemHandler = (key: string) => {
  70. if (key === params.current.search_game_name) return;
  71. setSearchValue(key);
  72. setSearchValueInit(key, false);
  73. };
  74. const removeHistoryItem = (event: MouseEvent<HTMLElement>, item: string) => {
  75. event.stopPropagation();
  76. removeKey(item);
  77. };
  78. const nextHandler = async () => {
  79. params.current.current_page++;
  80. return getGames().then((data) => data && setGames((games) => games.concat(data)));
  81. };
  82. return (
  83. <div className={"flex h-[100dvh] flex-col px-[0.12rem] py-[0.08rem]"}>
  84. <div className={"home-search flex-shrink-0"}>
  85. <SearchBar
  86. className={"rounded-[0.05rem] bg-[#191919]"}
  87. style={{
  88. "--background": "transparent",
  89. "--height": "0.3rem",
  90. }}
  91. aria-hidden="true"
  92. placeholder={t("search")}
  93. showCancelButton={() => true}
  94. ref={searchBarRef}
  95. // onChange={changeHandler}
  96. value={searchValue}
  97. onChange={(val) => setSearchValue(val)}
  98. onBlur={blurHandler}
  99. onCancel={onCancel}
  100. />
  101. <div
  102. className={
  103. "h-[.5rem] text-center text-[0.12rem] text-[#6e6e6e]" + " leading-[.5rem]"
  104. }
  105. >
  106. {t("searchTips")}
  107. </div>
  108. {history.length ? (
  109. <div className={"flex items-center justify-between"}>
  110. <header> {t("searchHistory")} </header>
  111. <i
  112. className="iconfont icon-guanbi cursor-pointer text-[0.08rem]"
  113. onClick={() => removeAllKey()}
  114. ></i>
  115. </div>
  116. ) : null}
  117. <div className={"mt-[0.05rem] flex flex-wrap"}>
  118. {history.map((item, index) => {
  119. return (
  120. <div
  121. className={
  122. "flex items-center bg-[#1a1a1a]" +
  123. " text-[#b3b3b3]" +
  124. " m-[0.05rem] rounded-[0.04rem] px-[0.07rem]" +
  125. " py-[0.03rem]"
  126. }
  127. onClick={() => historyItemHandler(item)}
  128. key={index}
  129. >
  130. <span className={"mr-[0.2rem]"}>{item}</span>
  131. <i
  132. className="iconfont icon-guanbi cursor-pointer text-[0.08rem]"
  133. onClick={(event) => removeHistoryItem(event, item)}
  134. ></i>
  135. </div>
  136. );
  137. })}
  138. </div>
  139. </div>
  140. <div className={"mt-[0.13rem] flex-1 overflow-y-scroll"}>
  141. {games.length ? (
  142. <GroupCard data={games} row={1} />
  143. ) : (
  144. <ErrorBlock
  145. status={isPending() ? "default" : "empty"}
  146. description={""}
  147. title={isPending() ? "" : "no data"}
  148. />
  149. )}
  150. <div className={"mt-[0.1rem]"}>
  151. {visible && (
  152. <Button
  153. fill={"none"}
  154. color={"default"}
  155. loading="auto"
  156. onClick={async () => {
  157. await nextHandler();
  158. }}
  159. block={true}
  160. style={{ "--background-color": "#1a1a1a", "--text-color": "#c4c4c4" }}
  161. >
  162. {t("searchButton")}
  163. </Button>
  164. )}
  165. </div>
  166. </div>
  167. </div>
  168. );
  169. };
  170. const HomeSearch: FC<PropsWithChildren<Props>> = (props) => {
  171. const router = useRouter();
  172. const t = useTranslations("HomePage");
  173. const [visible, setVisible] = useState(false);
  174. const handler = () => {
  175. router.push("/search");
  176. };
  177. return (
  178. <>
  179. <div
  180. onClick={handler}
  181. className={
  182. "flex items-center rounded-[0.03rem] rounded-[0.1rem] border border-[var(--primary-button)] px-[6px] py-[4px] text-[#6e6e6e]"
  183. }
  184. >
  185. <i
  186. className={
  187. "iconfont icon-sousuo mr-[0.0833rem] text-[0.14rem] text-[var(--textColor1)]"
  188. }
  189. ></i>
  190. <span className={"text-[0.12rem] text-[var(--textColor2)]"}>Nome do Jogo</span>
  191. </div>
  192. {/* <Mask visible={visible} opacity={0.9} getContainer={null}>
  193. <Content closeHandler={() => setVisible(false)} />
  194. </Mask> */}
  195. </>
  196. );
  197. };
  198. export default HomeSearch;